import React, { SyntheticEvent } from 'react'
import { message } from 'antd'
import moment from 'moment'
import { ITreeNode, IFileModel, IDepartmentInfo, DepartmentUserType, IRoleInfo } from '@/models/document'
import { FileTypes } from '@/models/common'
import eventBus, { EventBusEmitType } from '@/utils/eventbus'
import { HOST_URL_DEV, MQTT_URL_DEV } from './api'
import * as api from '@/api'
import { IUserModel } from '@/models/user'
message.config({
  top: 100
})
/**
 * @description 获取项目版本号
 * @returns 返回项目版本号
 */
function getVersion() {
  return "1.0.0"
}
/** 
 * @description 项目全局吐司提示
 * @param {string} [content] 吐司文案
 * @param {number} [duration] 吐司显示时长
 * @param {Function} [callback] 吐司关闭回调函数
 */
function alertTip(content?: string, duration?: number, callback?: () => void) {
  if (!content) return;
  message.info({
    content: content,
    duration: duration || 3,
    onClose: callback || undefined
  });
}
/**
 * @description 判断参数是否为空
 * @param {any} val 需要判断的数据
 */
function isNull(val: any) {
  if (val == null || val == "null" || val == "" || val == undefined || val == "undefined") {
    return null;
  } else {
    return val;
  }
}
/** 
 * @description 打开加载框
 * @param {string} [content] 加载框中的文案
 * @param {Function} [callback] 加载框关闭回调函数
 */
function loading(content?: string, key?: React.Key, callback?: () => void) {
  message.loading({
    content: content || '加载中...',
    duration: 0,
    key,
    onClose: callback
  });
}
/**
 * 修改加载框
 * @param content 
 * @param callback 
 * @param key 
 */
function updateLoading(type: "success" | "warning" | "error" | "loading" | "info", key: React.Key, content: string, duration: number, callback?: () => void,) {
  message[type]({
    content: content || '成功',
    duration: duration,
    key,
    onClose: callback
  });
}
/** 
 * @description 关闭加载框 
 */
function stopLoading() {
  message.destroy()
}
/**
 * @description 从url的查询参数中取值
 * @param {string} href url地址
 * @param {string} name 需要取值的参数名
 * @returns 返回参数值
 */
function getQueryString(href: string, name: string) {
  if (href.substr(0, 1) != '?') {
    href = '?' + href;
  }
  var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
  var r = href.substr(1).match(reg);
  if (r != null) return unescape(r[2]);
  return null;
}
/**
 * @description 数字不足两位前补0
 * @param {string | number} datastr 数字
 */
function addZero(datastr: number | string) {
  if (datastr as number < 10) {
    return "0" + datastr
  } else {
    return datastr
  }
}
/**
 * @description 将字典转换为跳转路由的字符串
 * @param {object} paramMap 键值对象:{key1:value1,key2:value2}
 * @returns {string} key1=value1&key2=value2
 */
function getContactParamsString(paramMap: { [key: string]: string }) {
  var str = "";
  for (let key in paramMap) {
    str = str + key + "=" + paramMap[key] + "&";
  }
  var str = str.substring(0, str.length - 1);
  return str;
}

/**
 * @description 倒计时
 * @param {number} staticTime 倒计开始时间，单位毫秒
 * @param {number} allTime 倒计总共时间，单位秒
 * @param {Function} fu 倒计时时间变化时触发
 * @param {Function} lastFu 倒计时完成时触发
 * @returns 返回结束倒计时函数
 */
function countDown(staticTime: number, allTime: number, fu: (surplusTime: number) => void, lastFu: (surplusTime: number) => void) {
  //倒计时id
  let timeFn: NodeJS.Timeout | undefined = undefined;
  if (timeFn) {
    clearInterval(timeFn);
    timeFn = undefined;
  }
  timeFn = setInterval(function () {
    var nowTime = new Date().getTime();
    var surplusTime = allTime - Math.floor((nowTime - staticTime) / 1000);
    if (surplusTime > 0) {
      fu(surplusTime);
    } else {
      clearInterval(timeFn);
      timeFn = undefined;
      lastFu(0);
    }
  }, 1000);
  return function () {
    clearInterval(timeFn);
    timeFn = undefined;
  }
}
/**
 * @description 检测是否登录
 */
const checkIsLogin = () => {
  return localStorage.getItem('token')
}
/**
 * @description 函数防抖
 */
const debounce = function () {
  let timer: any = null;
  return function (fn: () => void, delay: number) {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(fn, delay);
  }
}()

/**
 * @description 获取token
 */
function getToken() {
  return localStorage.getItem("token") || ""
}
/**
 * 取消事件冒泡
 * @param e
 */
function cancelBubble(e: SyntheticEvent) {
  e.stopPropagation()
  e.nativeEvent.stopImmediatePropagation()
}
/**
 * @description 是否是微信环境
 * @returns {boolean}
 */
function isWeiXin() {
  const ua = navigator.userAgent.toLowerCase();
  return /micromessenger/i.test(ua);
}
/**
 * @description 树形结构遍历
 * @param {ITreeNode<IFileModel>[]} tree 树
 * @param {Function} func 遍历每一个节点的回调函数
 */
const treeForEach = (tree: ITreeNode<IFileModel>[], func: (node: ITreeNode<IFileModel>, index: number) => void) => {
  tree.forEach((node, index) => {
    func(node, index)
    node.childrens && treeForEach(node.childrens, func)
  })
}
/**
 * @description 树形结构扁平化
 * @param {ITreeNode<IFileModel>[]} tree 树
 * @returns 
 */
const flatTree = (tree: ITreeNode<IFileModel>[]): ITreeNode<IFileModel>[] => {
  return tree.reduce((prev: ITreeNode<IFileModel>[], cur: ITreeNode<IFileModel>) => {
    const { childrens, ...res } = cur
    if (childrens && childrens.length) {
      return prev.concat(res, flatTree(childrens))
    } else {
      return prev.concat(res)
    }
  }, [])
}
/**
 * @description 删除树的某个节点
 * @param {ITreeNode<IFileModel>[]} tree 树
 * @param {string} id 节点唯一标识
 * @returns 
 */
const removeNodeInTree = (tree: any[], id: React.Key) => {
  if (!tree || !tree.length) {
    return
  }
  for (let i = 0; i < tree.length; i++) {
    if (tree[i].id === id) {
      tree.splice(i, 1);
      break;
    }
    const { children } = tree[i]
    if (children && children.length) {
      removeNodeInTree(children, id)
    }
  }
}
/**
 * @description 树的节点增加层级
 * @param {ITreeNode<IFileModel>[]} tree 树
 * @param {number} level 初始层级，默认0
 * @returns 
 */
const treeFlagLevel = (tree: ITreeNode<IFileModel>[], level: number) => {
  if (!tree || !tree.length) return;
  tree.forEach(item => {
    item.level = level;
    if (item.childrens && item.childrens.length) {
      treeFlagLevel(item.childrens, level + 1);
    }
  })
}
/**
 * @description 查找节点的所有父节点
 * @param {ITreeNode<IFileModel>[]} arr 树
 * @param {string} file_id 节点唯一标识
 * @returns {ITreeNode<IFileModel>[]} 所有父节点
 */
const findNodeParents = (arr: ITreeNode<IFileModel>[], file_id: React.Key) => {
  let stock: ITreeNode<IFileModel>[] = []
  let going = true
  var warker = function (arr: ITreeNode<IFileModel>[], file_id: React.Key) {
    arr.forEach(item => {
      if (!going) return
      stock.push(item)
      if (item.extra.file_id == file_id) {
        going = false
      } else if (item.childrens) {
        warker(item.childrens, file_id)
      } else {
        stock.pop()
      }
    })
    if (going) stock.pop()
  }
  warker(arr, file_id)
  return stock
}
/**
 * @description 组织架构遍历
 * @param {IDepartmentInfo[]} arr 组织架构列表
 * @param {Function} func 遍历每一个节点的回调函数
 */
const departmentForEach = (arr: any[], func: (node: any, index: number) => void) => {
  arr.forEach((node, index) => {
    func(node, index)
    node.childrens && departmentForEach(node.childrens, func)
  })
}
/**
 * @description 查找某个组织架构的所有父节点
 * @param {IDepartmentInfo[]} arr 树
 * @param {string} id 组织架构唯一标识
 * @returns {IDepartmentInfo[]} 所有父节点
 */
const findDepartmentParents = (arr: IDepartmentInfo[], id: React.Key) => {
  let stock: IDepartmentInfo[] = []
  let going = true
  var warker = function (arr: IDepartmentInfo[], id: React.Key) {
    arr.forEach(item => {
      if (!going) return
      stock.push(item)
      if (item.id == id && item.type == DepartmentUserType.D) {
        going = false
      } else if (item.childrens) {
        warker(item.childrens, id)
      } else {
        stock.pop()
      }
    })
    if (going) stock.pop()
  }
  warker(arr, id)
  return stock
}
/**
 * 获取文件类型
 * @param filetype 
 */
const getFileType = (filetype?: string) => {
  let defaultFileExt = FileTypes.UNKOWN
  if (!filetype) {
    return defaultFileExt
  }
  let fileExt = Reflect.get(FileTypes, filetype.toUpperCase())
  if (!fileExt) {
    return defaultFileExt
  }
  return fileExt
}

/**
 * 内置的预览文件
 */
const previewFile = (file: IFileModel, isMobile?: boolean, fromto?: string) => {
  const { file_id, file_type, file_url, changed_id = '' } = file
  const hrefStr = window.location.href
  const urlParams = new URL(hrefStr)
  const pathname = urlParams.pathname
  let origin = urlParams.origin
  let target = '_blank'
  if (isMobile) {
    target = '_self'
  }
  let from_to = fromto || ''
  if (file_type == FileTypes.XLSX || file_type == FileTypes.XLS) {//跳转普通表格
    const url = `/xlsheet?file_id=${file_id}&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.PPTX || file_type == FileTypes.PPT) {
    const url = `/xlpdf?file_id=${file_id}&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.DOCX || file_type == FileTypes.DOC) {//跳转word
    const url = `/xlword?file_id=${file_id}&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.ELT) {//跳转母表
    const url = `/xlelt?file_id=${file_id}&mode=1&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.ELS) {//跳转子表
    const url = `/xlels?file_id=${file_id}&mode=1&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.EMD ||
    file_type == FileTypes.EMT ||
    file_type == FileTypes.TXT
  ) {//跳转文档
    const url = `/xlemd?file_id=${file_id}&mode=1&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.PDF) {
    const url = `/xlpdf?file_id=${file_id}&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.EMIND || file_type == FileTypes.XMIND) {//跳转脑图
    const url = `/xlemind?file_id=${file_id}&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.IMAGE) {
    const url = `/xlimage?file_id=${file_id}&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.EVSD) {//跳转流程图
    const url = `/xlevsd?file_id=${file_id}&mode=1&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.MD || file_type == FileTypes.JSON) {//跳转Markdown
    const url = `/xlmarkdown?file_id=${file_id}&mode=1&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.ZIP) {//跳转zip
    const url = `/xlzip?file_id=${file_id}&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.VIDEO || file_type == FileTypes.AUDIO) {//跳转音视频
    const url = `/xlplayer?file_id=${file_id}&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.FRMT) {//表单模板
    const url = `/public/app/lowcode-form/build/preview.html?file_id=${file_id}&token=${getToken()}&mode=readonly`
    if (process.env.NODE_ENV == 'development') {
      origin = HOST_URL_DEV
    }
    window.open(`${origin}${url}`, target)
  } else if (file_type == FileTypes.FRM) {//表单
    const url = `/xlfrm?file_id=${file_id}&mode=1&changed_id=${changed_id}&from_to=${from_to}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else {
    if (file_url) {
      window.open(file_url, target)
    } else {
      return
    }
  }
}
/**
 * 内置的编辑文件
 */
const openFile = (file: IFileModel, isMobile?: boolean) => {
  const { file_id, file_type, file_url } = file
  const hrefStr = window.location.href
  const urlParams = new URL(hrefStr)
  const pathname = urlParams.pathname
  let origin = urlParams.origin
  let target = '_blank'
  if (isMobile) {
    target = '_self'
  }
  if (file_type == FileTypes.XLSX || file_type == FileTypes.XLS) {//跳转普通表格
    const url = `/onlyoffice?file_id=${file_id}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.PPTX || file_type == FileTypes.PDF || file_type == FileTypes.PPT) {//跳转onlyoffice页面
    const url = `/onlyoffice?file_id=${file_id}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.DOCX || file_type == FileTypes.DOC) {//跳转word
    const url = `/onlyoffice?file_id=${file_id}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.ELT) {//跳转母表
    const url = `/xlelt?file_id=${file_id}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.ELS) {//跳转子表
    const url = `/xlels?file_id=${file_id}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.EMD ||
    file_type == FileTypes.EMT ||
    file_type == FileTypes.TXT
  ) {//跳转文档
    const url = `/xlemd?file_id=${file_id}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.EMIND) {//跳转脑图
    const url = `/public/app/mind-map/index.html#/?file_id=${file_id}&token=${getToken()}`
    if (process.env.NODE_ENV == 'development') {
      origin = HOST_URL_DEV
    }
    window.open(`${origin}${url}`, target)
  } else if (file_type == FileTypes.EVSD) {//跳转流程图
    const url = `/xlevsd?file_id=${file_id}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.MD || file_type == FileTypes.JSON) {//跳转Markdown
    const url = `/xlmarkdown?file_id=${file_id}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else if (file_type == FileTypes.FRMT) {//表单模板
    const url = `/public/app/lowcode-form/build/index.html?file_id=${file_id}&token=${getToken()}`
    if (process.env.NODE_ENV == 'development') {
      origin = HOST_URL_DEV
    }
    window.open(`${origin}${url}`, target)
  } else if (file_type == FileTypes.FRM) {//表单
    const url = `/xlfrm?file_id=${file_id}`
    window.open(`${origin}${pathname}#${url}`, target)
  } else {
    if (file_url) {
      window.open(file_url, target)
    } else {
      return
    }
  }
}

/**
 * 打开图库浏览页面
 */
const openGalleryPage = (file_id: React.Key) => {
  const hrefStr = window.location.href
  const urlParams = new URL(hrefStr)
  const pathname = urlParams.pathname
  let origin = urlParams.origin
  let target = '_blank'
  const url = `/xlgallerybrowser?file_id=${file_id}`
  window.open(`${origin}${pathname}#${url}`, target)
}
/**
 * 获取评论的相对时间
 * @param order_date 
 */
const getCommentTime = (order_date: string) => {
  const serverTime = moment().valueOf()
  const createTime = moment(order_date).valueOf()
  const interval = (serverTime - createTime) / 1000
  if (interval < 60) {
    return '刚刚'
  } else if (interval < 60 * 60) {
    let tempTime = Math.floor(interval / 60)
    return `${tempTime}分钟前`
  } else if (interval < 60 * 60 * 24) {
    let tempTime = Math.floor(interval / (60 * 60))
    return `${tempTime}小时前`
  } else if (interval < 60 * 60 * 24 * 2) {
    if (interval < 24 * 60 * 60) {
      return '昨天';
    } else {
      return '前天'
    }
  } else if (interval < 60 * 60 * 24 * 7) {
    let tempTime = Math.floor(interval / (60 * 60 * 24))
    return `${tempTime}天前`
  } else if (interval < 60 * 60 * 24 * 365) {
    return moment(createTime - 0).format('MM-DD')
  } else {
    return moment(createTime - 0).format('YYYY-MM-DD')
  }
}
/**
 * 将ArrayBuffer转换成字符串
 * @param buffer ArrayBuffer
 */
const arrayBufferToString = (buffer: ArrayBuffer, encoding = 'utf-8') => {
  return new Promise((resolve, reject) => {
    var resBlob = new Blob([buffer])
    var reader = new FileReader()
    reader.readAsText(resBlob, encoding)
    reader.onload = () => {
      resolve(reader.result)
    }
    reader.onerror = () => {
      reject(JSON.stringify({}))
    }
  })
}

/**
 * 将字符串转换成ArrayBuffer
 */
const stringToArrayBuffer = (dataStr: string) => {
  return new Promise<ArrayBuffer>((resolve, reject) => {
    var blob = new Blob([dataStr], {
      type: 'application/json'
    })
    var reader = new FileReader()
    reader.readAsArrayBuffer(blob)
    reader.onload = () => {
      resolve(reader.result as ArrayBuffer)
    }
    reader.onerror = () => {
      reject()
    }
  })
}
/**
 * 文件转换成ArrayBuffer
 * @param file 
 */
const fileToArrayBuffer = (file: File) => {
  return new Promise((resolve, reject) => {
    var reader = new FileReader()
    reader.readAsArrayBuffer(file)
    reader.onload = () => {
      resolve(reader.result)
    }
    reader.onerror = () => {
      reject()
    }
  })
}

const getInitUserInfo = (): IUserModel => {
  let userinfo = localStorage.getItem("userinfo")
  if (userinfo) {
    return JSON.parse(userinfo) as IUserModel
  } else {
    return {
      token: '',
      name: '',
      user_nickname: '',
      user_avatar: '',
      avatar_id: -1,
      department_name: '',
      user_type: 0,//用户类型（-1后台管理员，0普通人员，1平台超级管理员）
      is_force_edit_password: 0,//是否强制修改密码（0不是，1是）
      department_id: "",
      tenant_id: "",
      tenant_name: "",
      tenant_logo: "",
      user_id: "",
      mqtt_client_id: "",
      system_name: "",
      mqtt_host: "",
      yjs_url: "",
      onlyoffice_host: "",
    }
  }
}

const getGuid = (prefix?: String) => {
  let counter = 0
  let guid = (+new Date()).toString(32),
    i = 0
  for (; i < 5; i++) {
    guid += Math.floor(Math.random() * 65535).toString(32)
  }
  return (prefix || 'wu_') + guid + (counter++).toString(32)
}

const clearElement = (element: HTMLElement | null): void => {
  element && element.childNodes.forEach(node => element.removeChild(node))
}

/**
 * 导出文件
 */
const exportFile = async (file_id: React.Key, type: string, file_name: string, param_file?: ArrayBuffer) => {
  
}

const getPhoneReg = () => {
  const phone_reg = /^1[3456789]\d{9}$/
  return phone_reg
}

const getVerifyCodeReg = () => {
  const verifycode_reg = /^\d{6}$/
  return verifycode_reg
}

const injectJS = (src: string, onload?: () => void) => {
  return new Promise((resolve, reject) => {
    const loaded = Array.from(document.scripts).some(it => it.getAttribute('src') === src); // Warn：script.src !== script.getAttribute('src')
    if (loaded) {
      typeof onload === 'function' && onload();
      resolve(window)
      return;
    }
    const script = document.createElement('script');
    script.src = src;
    script.type = 'text/javascript';
    script.addEventListener('load', (ev) => {
      typeof onload === 'function' && onload();
      resolve(window)
    });
    document.head.appendChild(script);
  })
}

const injectCss = (href: string, onload?: () => void) => {
  return new Promise((resolve, reject) => {
    const linkTags = document.querySelectorAll("link");
    const loaded = Array.from(linkTags).some(it => it.getAttribute('href') === href);
    if (loaded) {
      typeof onload === 'function' && onload();
      resolve(href)
      return;
    }
    const style = document.createElement('link');
    style.href = href;
    style.rel = 'stylesheet'
    style.type = 'text/css';
    style.addEventListener('load', (ev) => {
      typeof onload === 'function' && onload();
      resolve(href)
    });
    document.head.appendChild(style);
  })
}

/**
 * Determine if a value is a FormData
 *
 * @param {*} thing The value to test
 *
 * @returns {boolean} True if value is an FormData, otherwise false
 */
const isFormData = (thing: any) => {
  const pattern = '[object FormData]';
  return thing && (
    (typeof FormData === 'function' && thing instanceof FormData) ||
    toString.call(thing) === pattern
  );
}
/**
 * 删除search参数
 * @returns 
 */
const removeSearchParam = (url: string, key: string) => {
  // 如果URL中包含查询字符串
  if (url.indexOf('?') > -1) {
    // 拆分URL和查询字符串
    let urlParts = url.split('?');
    let queryString = urlParts[1];

    // 拆分查询字符串为键值对
    let queries = queryString.split('&');
    let i;

    // 移除包含指定键的键值对
    for (i = 0; i < queries.length; i++) {
      if (queries[i].indexOf(key + '=') === 0) {
        queries.splice(i, 1);
        break;
      }
    }

    // 构建新的查询字符串
    let newQueryString = queries.join('&');

    // 如果新查询字符串为空，则移除问号
    if (newQueryString === '') {
      url = urlParts[0];
    } else {
      // 重新拼接URL和查询字符串
      url = urlParts[0] + '?' + newQueryString;
    }
  }

  return url;
}

/**
 * @file 工具函数类
 */
export default {
  openGalleryPage,
  removeSearchParam,
  isFormData,
  injectCss,
  injectJS,
  getVerifyCodeReg,
  getPhoneReg,
  getInitUserInfo,
  exportFile,
  clearElement,
  getGuid,

  fileToArrayBuffer,
  stringToArrayBuffer,
  arrayBufferToString,
  getCommentTime,
  previewFile,
  openFile,
  getFileType,
  departmentForEach,
  findDepartmentParents,
  findNodeParents,
  treeFlagLevel,
  removeNodeInTree,
  treeForEach,
  flatTree,
  isWeiXin,
  cancelBubble,
  debounce,
  getToken,
  getVersion,
  alertTip,
  getContactParamsString,
  loading,
  stopLoading,
  updateLoading,
  isNull,
  getQueryString,
  addZero,
  countDown,
  checkIsLogin,
}